<?php

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

require_once 'WSUser.php';
class WSServer {

    private $master = null;
    private $sockets = array();
    private $users = array();
    private $debug = false;
    private $groups = array();
    private $frees = array();
    private $rights = array();  // cau tra loi dung
    private $count = array();   // so lan request cua server
    private $playing = array();
    private $questions = array();
    private $type_question = array();
    private $iNumQuestion = 30;
    

    public function __construct($host = "localhost", $port = 85) {
        $this->master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die("socket_create() failed");
        socket_set_option($this->master, SOL_SOCKET, SO_REUSEADDR, 1) or die("socket_option() failed");
        socket_bind($this->master, $host, $port) or die("socket_bind() failed");
        socket_listen($this->master, 20) or die("socket_listen() failed");
        echo "Server Started : " . date('Y-m-d H:i:s') . "\n";
        echo "Master socket  : " . $this->master . "\n";
        echo "Listening on   : " . $host . " port " . $port . "\n\n";

        // Add master to array sockets
        $this->sockets[] = $this->master;

        $connection = mysql_connect("localhost", "root", "");
        if( !$connection)
            die("Not connected: ". mysql_error ());
        mysql_select_db("toihoctienganh", $connection)
            or die("Could not select DB" . mysql_error());
            $query = "SELECT iNumQuestion FROM global WHERE id = 1";
            $result = mysql_query($query, $connection) or die("Could not connect").mysql_error();
            $set = mysql_fetch_row($result);
            $this->iNumQuestion =$set[0];
            mysql_close($connection);


        return $this;
    }

    public function run() {
        while (true) {
            $changed = $this->sockets;
            @socket_select($changed, $write = NULL, $except = NULL, 1);
            foreach ($changed as $socket) {
                if ($socket == $this->master) {
                    $client = @socket_accept($this->master);
                    if ($client < 0) {
                        $this->console("socket_accept() failed.\n");
                        continue;
                    } else {
                        $user = $this->connect($client);
                        $this->users[$client] = $user;
                        $this->sockets[] = $client;
                    }
                } else {
                    $user = $this->users[$socket];
                    $bytes = socket_recv($socket, $buffer, 2048, MSG_WAITALL);
                    if ($bytes == 0) {

                        $this->disconnect($user);
                        // continue;
                    } else {
                        if (!$user->handshake) {
                            $this->dohandshake($user, $buffer);
                        } else {
                            $this->process($user, $buffer);
                        }
                    }
                }
            }
        }
    }

    public function connect($socket) {
        global $CONFIG;
        $user = new WSUser($this, $socket);
        $this->console($socket . " CONNECTED!");
        return $user;
    }

    public function disconnect($user) {	
	$this->outFreesArray($user);
        $key = $this->findGroup($user);
        if(count($this->groups[$key]) > 1 )
             if($this->groups[$key][1]->getName() != 0){
                $host = $this->getHost($key);
                if( $host == $user){ // if player quit game is host
                    $this->setHost($user, $key);
                }
        }

        $user->outGroup();
        $this->outGroup($user);
        // send Quit for user in this room,
        if( $key >= 0 && count($this->groups[$key]) > 0 && $this->groups[$key][0]->getName() != 0){     // user is player of room and room has another player
            $room = new Room();
            $host = $this->getHost($key);//return host of this room
            $guid = $host->getName();//return GUID
            for( $i = 0 ; $i < count($this->groups[$key]) ; ++$i){
                $room->name[] = $this->get_user($this->groups[$key][$i]->getName());
                $room->player[] = $this->groups[$key][$i]->getName();
                $room->ready[] = $this->groups[$key][$i]->getReady();
                $room->host = $guid;
            }
             $msg = $this->wrap("QUIT_GAME", "", json_encode($room));
             $this->broadcast_group($user, $key, $msg);
        }

        $room = $this->getListRoom(1);
        $msg = $this->wrap("LIST_ROOM", "", json_encode($room));
        $this->broadcast($msg);
		

        $socketKey = array_search($user, $this->users);
        $sKey = array_search($socketKey, $this->sockets);

        if ($socketKey && ($sKey>=0)) {
            unset($this->users[$socketKey]);
            array_splice($this->sockets, $sKey, 1);
        }

        $this->console($user->socket . " DISCONNECTED!");
    }

    public function process($user, $data) {
        $decodedData = '';
        if (
                strpos($data, chr(129)) !== false ||
                strpos($data, chr(1)) !== false ||
                strpos($data, chr(130) !== false)
        ) {
            $decodedData = $this->_hybiDecode($data);
        } else if (strpos($data, chr(137)) !== false) {
            $decodedData = pack('C', 0x8a) . $this->_hybiDecode($data);
            $this->send($user->socket, $decodedData);
            $this->disconnect($user->socket);
            return false;
        } else {
            $this->disconnect($user->socket);
            return false;
        }
        $this->onData($decodedData, $user);
        return true;
    }

    public function onData($jData, $user) {
        $data = json_decode($jData);

        switch (isset($data->type) ? $data->type : null) {

            case 'LOGIN':                
                $author = $data->author; // get guid
                $user->setName(intval($author)); // name is guid of user entity
                
                // Check if account is playing
                for( $i = 0 ; $i < count($this->groups) ; $i++)
                    for( $j = 0; $j < count($this->groups[$i]) ; $j++)
                        if( $this->groups[$i][$j] == $user){
                            $msg = $this->wrap("LOGIN", $author, "-1");
                            $this->send($user->socket, $msg);
                            return;
                        }
                $a =  count($this->frees);
                for($k = 0 ; $k < $a ; $k++)
                    if( $this->frees[$k]->getName() == $user->getName()){
                        $msg = $this->wrap("LOGIN", $author, "-1");
                        $this->send($user->socket, $msg);
                        return;
                    }
                $this->frees[] = $user;
                $msg = $this->wrap("LOGIN", $author, "1");
                $this->send($user->socket, $msg);
                return;
                break;

            case 'LIST_ROOM':
                   // this player is free
                $current = intval($data->content);
                
                $author = $data->author;
                // goi so luong phong va so luong nguoi o moi phong
                $room = $this->getListRoom($current);
                $msg = $this->wrap("LIST_ROOM", $author, json_encode($room));
                $this->send($user->socket, $msg);
                return;
                break;
            case 'NEW_ROOM':
                $key = $this->getLargestKey();
                if($user->setGroup($key)){
                    $this->type_question[$key]=1;
                    $this->playing[$key] = 0;
                    $this->outFreesArray($user);
                    $user->setHost(1); // is Host
                    $author = $data->author;
                    $msg = $this->wrap("NEW_ROOM", $author, 1);
                    $this->send($user->socket, $msg);

                    $room = new Room();

                    $host = $this->getHost($key);//return host of this room
                    for( $i = 0 ; $i < count($this->groups[$key]) ; ++$i){
                        $room->player[] = $this->groups[$key][$i]->getName();
                        $room->name[] = $this->get_user($this->groups[$key][$i]->getName());
                        $room->ready[] = $this->groups[$key][$i]->getReady();
                        $room->host = $host->getName();
                    }
                    $msg = $this->wrap("JOIN_ROOM", $author, json_encode($room));
                    $this->send($user->socket, $msg);

                    $room = $this->getListRoom(1);
                    $msg = $this->wrap("LIST_ROOM", $author, json_encode($room));
                    $this->broadcast($msg);
                }
                else{
                    $msg = $this->wrap("NEW_ROOM", $author, 0);
                    $this->send($user->socket, $msg);
                }
                return;
                break;
            case 'PLAY_WITH_PC':
                $author = $data->author;
                $key = $this->findGroup($user);
                //if($user->setGroup($key)){
                    
                    $this->outFreesArray($user);
                    $user->setHost(1);

                    $pc = new WSUser($this, "");
                    $pc->setName(0);
                    $pc->setReady(1);
                    $pc->setGroup($key);

                    $this->playing[$key] = 1;
                            
                    $room = new Room();
                    $host = $this->getHost($key);//return host of this room
                    for( $i = 0 ; $i < count($this->groups[$key]) ; ++$i){
                        $room->player[] = $this->groups[$key][$i]->getName();
                        $room->ready[] = $this->groups[$key][$i]->getReady();
                        $room->host = $host->getName();
                        if( $this->get_user($this->groups[$key][$i]->getName()) != -1){
                            $room->name[] = $this->get_user($this->groups[$key][$i]->getName());
                        }
                        else{
                            $room->name[] = "Nobita";
                        }
                    }
                    $msg = $this->wrap("JOIN_ROOM", $author, json_encode($room));
                    $this->send($user->socket, $msg);

                    $this->count[$key] = 0;
                    unset($this->rights[$key]);

                    $msg = $this->wrap("START_GAME", $author, json_encode($author));
                    $this->send($user->socket, $msg);

//                    if( $content == 1){ // question from question bank
                    $this->questions[$key] = $this->getListQuestion1();
//                }
//                else{ //question from calendar
//                    $this->questions[$key] = $this->getQuestion_fromCalendar($key);
//                }
                //}
                return;
                break;
            case 'JOIN_ROOM':
                $author = $data->author;
                $key = intval($data->content);
                // send msg include users in that room
                if( $user->setGroup($key)){
                    $this->outFreesArray($user);
                    $room = new Room();
                    $host = $this->getHost($key);//return host of this room
                    $guid = $host->getName();//return GUID
                    for( $i = 0 ; $i < count($this->groups[$key]) ; ++$i){
                        $room->name[] = $this->get_user($this->groups[$key][$i]->getName());
                        $room->player[] = $this->groups[$key][$i]->getName();
                        $room->ready[] = $this->groups[$key][$i]->getReady();
                        $room->host = $guid;
                    }
                    $msg = $this->wrap("JOIN_ROOM", $author, json_encode($room));
                    $this->broadcast_group(null, $key, $msg);

                    //broadcast for the players which dont in any group
                    $room = $this->getListRoom(1);
                    $msg = $this->wrap("LIST_ROOM", $author, json_encode($room));
                    $this->broadcast($msg);
                }
                else{
                    $msg = $this->wrap("JOIN_ROOM", $author, "Full");
                    $this->send($user->socket, $msg);
                }
                return;
                break;
            case 'READY':
                $author = $data->author;
                $key = $this->findGroup($user);
                if($key >= 0){
                    $user->setReady(1);
                    $room = new Room();
                    $host = $this->getHost($key);//return host of this room
                    $guid = $host->getName();//return GUID
                    for( $i = 0 ; $i < count($this->groups[$key]) ; ++$i){
                        $room->name[] = $this->get_user($this->groups[$key][$i]->getName());
                        $room->player[] = $this->groups[$key][$i]->getName();
                        $room->ready[] = $this->groups[$key][$i]->getReady();
                        $room->host = $guid;
                    }
                    $msg = $this->wrap("READY", $author, json_encode($room));
                    $this->broadcast_group(null, $key, $msg);
                }
                return;
                break;
            case 'UNREADY':
                $author = $data->author;
                $key = $this->findGroup($user);
                if($key >= 0){
                    $user->setReady(0);
                    $room = new Room();
                    $host = $this->getHost($key);//return host of this room
                    $guid = $host->getName();//return GUID
                    for( $i = 0 ; $i < count($this->groups[$key]) ; ++$i){
                        $room->name[] = $this->get_user($this->groups[$key][$i]->getName());
                        $room->player[] = $this->groups[$key][$i]->getName();
                        $room->ready[] = $this->groups[$key][$i]->getReady();
                        $room->host = $guid;
                    }
                    $msg = $this->wrap("UNREADY", $author, json_encode($room));
                    $this->broadcast_group(null, $key, $msg);
                }
                return;
                break;
            case 'HAVE_RIGHT_ANSWER':
                $author = $data->author;
                $key = $this->findGroup($user);
                $content = intval($data->content);
                if($key >= 0){
                    $this->count[$key]++;
                    if( $content == 1){
                        $this->rights[$key][] = $author;
                        
                    }
                }
                if( $this->count[$key] == 1 && $this->groups[$key][1]->getName() == 0)
                {
                    $rand = rand(0, 1);
                    if( $rand == 1)
                    {
                        $this->rights[$key][] = $this->groups[$key][1]->getName();
                    }
                    if( $this->rights[$key] != null)
                        $msg = $this->wrap("HAVE_RIGHT_ANSWER", $author, json_encode($this->rights[$key]));
                    else
                        $msg = $this->wrap("HAVE_RIGHT_ANSWER", $author, -1);
                    $this->send($user->socket, $msg);
                    $this->count[$key] = 0;
                    return;
                }
                if( $this->count[$key] == count($this->groups[$key]) )
                        if( $this->rights[$key] != null){
                            $msg = $this->wrap("HAVE_RIGHT_ANSWER", $author, json_encode($this->rights[$key]));
                            $this->broadcast_group(null, $key, $msg);
                            $this->count[$key] = 0;
                        }
                        else{
                            $msg = $this->wrap("HAVE_RIGHT_ANSWER", $author, -1);
                            $this->broadcast_group(null, $key, $msg);
                            $this->count[$key] = 0;
                        }
                return;
                break;
            case 'FINISH_GAME': // who is winner, and back to room
		$author = $data->author;
                $key = $this->findGroup($user);
                $this->playing[$key] = 0;
                
                if($key >= 0){
                    $this->count[$key]++;
                }
                if( $this->count[$key] == 1 && $this->groups[$key][1]->getName() == 0){
                    $msg = $this->wrap("FINISH_GAME", $author, json_encode($author));
                    $this->send($user->socket, $msg);
                    
                }

                else if( $this->count[$key] == count($this->groups[$key]) ){
                    $msg = $this->wrap("FINISH_GAME", $author, json_encode($author)); // broadcast to player who is winner
                    $this->broadcast_group(null, $key, $msg);
                    
                    for( $i = 0 ; $i < count($this->groups[$key]) ; ++$i){
                        $this->groups[$key][$i]->setReady(0);
                    }
                    $host = $this->getHost($key);//return host of this room
                    $guid = $host->getName();//return GUID
                    $room = new Room();
                    for( $i = 0 ; $i < count($this->groups[$key]) ; ++$i){
                        $room->name[] = $this->get_user($this->groups[$key][$i]->getName());
                        $room->player[] = $this->groups[$key][$i]->getName();
                        $room->ready[] = $this->groups[$key][$i]->getReady();
                        $room->host = $guid;
                    }
                    $msg = $this->wrap("UNREADY", $author, json_encode($room));
                    $this->broadcast_group(null, $key, $msg);
                }

                unset ($this->questions[$key]); //Xoa array question
                return;
                break;
            case 'QUIT_ROOM':
                $flag = 0;
                $this->frees[] = $user;
                $author = $data->author;
                $key = $this->findGroup($user);
                if( count($this->groups[$key]) > 1)
                    if($this->groups[$key][1]->getName() != 0){
                        $host = $this->getHost($key);
                        if( $host == $user){ // if player quit game is host
                            $flag = $this->setHost($user, $key);
                        }
                    }
                    else{ // PLAY WITH PC
                        array_splice($this->groups, $key, 1);
                    }
                $user->outGroup();
                $this->outGroup($user);
                if( $flag){ // if could set new host, send to player in this room about changed
                    $room = new Room();
                    $host = $this->getHost($key);//return host of this room
                    $guid = $host->getName();//return GUID
                    for( $i = 0 ; $i < count($this->groups[$key]) ; ++$i){
                        $room->name[] = $this->get_user($this->groups[$key][$i]->getName());
                        $room->player[] = $this->groups[$key][$i]->getName();
                        $room->ready[] = $this->groups[$key][$i]->getReady();
                        $room->host = $guid;
                    }
                    $msg = $this->wrap("QUIT_ROOM", "", json_encode($room));
                    $this->broadcast_group($user, $key, $msg);
                }
                $room = $this->getListRoom(1);
                $msg = $this->wrap("LIST_ROOM", $author, json_encode($room));
                $this->broadcast($msg);
                return;
                break;
            case 'KICK_ROOM':
                $author = $data->author;
                $content = intval($data->content);
                $key = $this->findGroup($user);
                for( $i = 0 ; $i < count($this->groups[$key]) ; ++$i){
                    if( $this->groups[$key][$i]->getName() == $content){
                        $msg = $this->wrap("BI_KICK_ROOM", "", json_encode($author));
                        $this->send($this->groups[$key][$i]->socket, $msg);

                        $this->groups[$key][$i]->outGroup();
                        $this->frees[] = $this->groups[$key][$i];
                        $this->outGroup($this->groups[$key][$i]);

                        $room = new Room();
                        $host = $this->getHost($key);//return host of this room
                        $guid = $host->getName();//return GUID
                        for( $j = 0 ; $j < count($this->groups[$key]) ; ++$j){
                            $room->name[] = $this->get_user($this->groups[$key][$j]->getName());
                            $room->player[] = $this->groups[$key][$j]->getName();
                            $room->ready[] = $this->groups[$key][$j]->getReady();
                            $room->host = $guid;
                        }
                        $msg = $this->wrap("KICK_ROOM", "", json_encode($room));
                        $this->broadcast_group($this->groups[$key][$i], $key, $msg);

                        $room = $this->getListRoom(1);
                        $msg = $this->wrap("LIST_ROOM", $author, json_encode($room));
                        $this->broadcast($msg);
                        break;
                    }
                }

                return;
                break;
            case 'LIST_FREE_PLAYER':
                $author = $data->author;
                $list_free = array();
                $list_free = $this->frees;
                $names=array();
                for($i = 0 ; $i < $list_free ; ++$i){
                    $names[] = $this->get_user($this->frees[$i]->getName());
                }
                $list_free[] = $name;
                $msg = $this->wrap("LIST_FREE_PLAYER", $author, json_encode($list_free));
                $this->send($user->socket, $msg);
                return;
                break;
            case 'INVITE':
                $author = $data->author;
                $key = $this->findGroup($user);
                $content = intval($data->content);
                $msg = $this->wrap("INVITE", $author, json_encode($content));
                $this->send($this->frees[$content]->socket, $msg);
                return;
                break;
            case 'START_GAME':
                $author = $data->author;
                $content = intval($data->content);
                $key = $this->findGroup($user);
                $this->playing[$key] = 1;
                $this->count[$key] = 0;
                unset($this->rights[$key]);

                $msg = $this->wrap("START_GAME", $author, json_encode($author));
                $this->broadcast_group(null, $key, $msg);

                if( $content == 1){ // question from question bank
                    $this->questions[$key] = $this->getListQuestion1();
                }
                else if( $content == 0){ //question from calendar
                    $this->questions[$key] = $this->getQuestion_fromCalendar($key);
                }
                return;
                break;
            case 'DRAW_QUES':
                 $author = $data->author;
                 $content = $data->content; // type of question
                 $key = $this->findGroup($user);
//                 if( count($this->questions[$key]) == 0){
//                     if( $content == 1){ // question from question bank
//                        $this->questions[$key] = $this->getListQuestion1();
//                    }
//                    else{ //question from calendar
//                        $this->questions[$key] = $this->getQuestion_fromCalendar($key);
//                    }
//                 }
                 if($this->questions[$key][0]){
                     $questionList = $this->questions[$key][0];
                     $msg = $this->wrap("DRAW_QUES", $author, json_encode($questionList));
                     if( $this->groups[$key][1]->getName() != 0)
                        $this->broadcast_group(null, $key, $msg);
                     else
                         $this->send($user->socket, $msg);

                    $this->count[$key] = 0;
                    unset($this->rights[$key]);

                    array_splice($this->questions[$key], 0, 1);
                 }
                 else{ // FINISH GAME
                     $msg = $this->wrap("OUT_OF_QUESTION", $author, 1);
                     if( $this->groups[$key][1]->getName() != 0)
                        $this->broadcast_group(null, $key, $msg);
                     else
                         $this->send($user->socket, $msg);
                 }
                return;
                break;
            case 'MESSAGE_PUBLIC':
                $author = intval($data->author);

                $content = array();
                $name = $this->get_user($author);
                $content[] = $name;
                $content[] = $data->content;
                
                $msg = $this->wrap("MESSAGE_PUBLIC", $author, json_encode($content));
                $this->broadcast($msg);

                return;
                break;
            case 'MESSAGE':
                $author = intval($data->author);
                $content = array();
                $name = $this->get_user($author);
                $content[] = $name;
                $content[] = $data->content;
                $key = $this->findGroup($user);
                if( count($this->groups[$key]) > 1)
                    if($this->groups[$key][1]->getName() != 0){
                        $msg = $this->wrap("MESSAGE", $author, json_encode($content));
                        $this->broadcast_group(null, $key, $msg);
                        return;
                    } 
                $msg = $this->wrap("MESSAGE", $author, json_encode($content));
                $this->send($user->socket, $msg);
                return;
                break;
            case "TYPE_QUESTION":
                    $author = $data->author;
                    $content = intval($data->content); // type of question
                    $key = $this->findGroup($user);
                    $this->type_question[$key]=$content;

                    $room = $this->getListRoom(1);
                    $msg = $this->wrap("LIST_ROOM", $author, json_encode($room));
                    $this->broadcast($msg);

                    if( count($this->groups[$key]) > 1)
                        if($this->groups[$key][1]->getName() != 0){
                            $msg = $this->wrap("TYPE_QUESTION", $author, json_encode($content));
                            $this->broadcast_group(null, $key, $msg);
                            return;
                        }
                return;
                break;
            default:
                break;
        }
    }

    public function send($client, $msg) {
        $this->console("> " . $msg);
        $encodedData = $this->_hybiEncode($msg, false);
        if (!socket_write($client, $encodedData, strlen($encodedData))) {
            $this->disconnect($client);
        }
    }

    public function dohandshake($user, $buffer) {
        $this->console("\nRequesting handshake...");
        list($resource, $host, $origin, $strkey, $data) = $this->getheaders($buffer);
        $this->console("Handshaking...");

        if ($strkey == "") {
            socket_close($user->socket);
            $this->console('failed');
            return false;
        }
        $strkey .= '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
        $strkey = sha1($strkey, true);
        $strkey = base64_encode($strkey);

        $upgrade = "HTTP/1.1 101 Switching Protocols\r\n".
                    "Upgrade: websocket\r\n".
                    "Connection: Upgrade\r\n".
                    "Sec-WebSocket-Accept: " . $strkey . "\r\n".
                    "Sec-WebSocket-Protocol: chat\r\n\r\n";

        socket_write($user->socket, $upgrade, strlen($upgrade));
        $user->handshake = true;
        $this->console("Done handshaking...");
    }

    public function getheaders($req) {
        $r = $h = $o = $key = $data = null;
        if (preg_match("/GET (.*) HTTP/", $req, $match)) {
            $r = $match[1];
        }
        if (preg_match("/Host: (.*)\r\n/", $req, $match)) {
            $h = $match[1];
        }
        if (preg_match("/Origin: (.*)\r\n/", $req, $match)) {
            $o = $match[1];
        }

        if (preg_match("/\r\n(.*?)\$/", $req, $match)) {
            $data = $match[1];
        }

        if (preg_match("/Sec-WebSocket-Key: (.*)\r\n/", $req, $match)) {
            $key = $match[1];
        }
        return array($r, $h, $o, $key, $data);
    }

    public function getuserbysocket($socket) {
        $found = null;
        foreach ($this->users as $user) {
            if ($user->socket == $socket) {
                $found = $user;
                break;
            }
        }
        return $found;
    }

    public function _hybiEncode($data, $binary) {
        $databuffer = array();
        $sendlength = strlen($data);
        $rawBytesSend = $sendlength + 2;
        $packet;

        if ($sendlength > 65535) {
            // 64bit
            array_pad($databuffer, 10, 0);
            $databuffer[1] = 127;
            $lo = $sendlength | 0;
            $hi = ($sendlength - $lo) / 4294967296;

            $databuffer[2] = ($hi >> 24) & 255;
            $databuffer[3] = ($hi >> 16) & 255;
            $databuffer[4] = ($hi >> 8) & 255;
            $databuffer[5] = $hi & 255;

            $databuffer[6] = ($lo >> 24) & 255;
            $databuffer[7] = ($lo >> 16) & 255;
            $databuffer[8] = ($lo >> 8) & 255;
            $databuffer[9] = $lo & 255;

            $rawBytesSend += 8;
        } else if ($sendlength > 125) {
            // 16 bit
            array_pad($databuffer, 4, 0);
            $databuffer[1] = 126;
            $databuffer[2] = ($sendlength >> 8) & 255;
            $databuffer[3] = $sendlength & 255;

            $rawBytesSend += 2;
        } else {
            array_pad($databuffer, 2, 0);
            $databuffer[1] = $sendlength;
        }

        // Set op and find
        $databuffer[0] = (128 + ($binary ? 2 : 1));
        $packet = pack('c', $databuffer[0]);
        // Clear masking bit
        //$databuffer[1] &= ~128;
        // write out the packet header
        for ($i = 1; $i < count($databuffer); $i++) {
            //$packet .= $databuffer[$i];
            $packet .= pack('c', $databuffer[$i]);
        }

        // write out the packet data
        for ($i = 0; $i < $sendlength; $i++) {
            $packet .= $data[$i];
        }

        return $packet;
    }

    public function encode($payloadData) {
                $payloadLength = strlen($payloadData);

                $firstByte = 0x01;
                $FIN = true;

                $firstByte += $FIN * 128;

                $encoded = chr($firstByte);

                if ($payloadLength <= 125) {
                        $secondByte = $payloadLength;
                        $secondByte += 0 * 128;

                        $encoded .= chr($secondByte);
                } else if ($payloadLength <= 255 * 255 - 1) {
                        $secondByte = 126;
                        $secondByte += 0 * 128;

                        $encoded .= chr($secondByte) . pack("n", $payloadLength);
                } else {
                        // TODO: max length is now 32 bits instead of 64 !!!!!
                        $secondByte = 127;
                        $secondByte += 0 * 128;

                        $encoded .= chr($secondByte);
                        $encoded .= pack("N", 0);
                        $encoded .= pack("N", $payloadLength);
                }

                $key = 0;
//                if ($this -> mask) {
//                        $key = pack("N", rand(0, pow(255, 4) - 1));
//                        $encoded .= $key;
//
//                }

                if ($payloadData)
                        $encoded .= $payloadData;

                return $encoded;
        }

    public function _hybiDecode($data)    {
        $bytes = $data;
        $dataLength = '';
        $mask = '';
        $coded_data = '';
        $decodedData = '';
        $secondByte = sprintf('%08b', ord($bytes[1]));
        $masked = ($secondByte[0] == '1') ? true : false;
        $dataLength = ($masked === true) ? ord($bytes[1]) & 127 : ord($bytes[1]);

        if ($masked === true) {
            if ($dataLength === 126) {
                $mask = substr($bytes, 4, 4);
                $coded_data = substr($bytes, 8);
            } elseif ($dataLength === 127) {
                $mask = substr($bytes, 10, 4);
                $coded_data = substr($bytes, 14);
            } else {
                $mask = substr($bytes, 2, 4);
                $coded_data = substr($bytes, 6);
            }
            for ($i = 0; $i < strlen($coded_data); $i++) {
                $decodedData .= $coded_data[$i] ^ $mask[$i % 4];
            }
        } else {
            if ($dataLength === 126) {
                $decodedData = substr($bytes, 4);
            } elseif ($dataLength === 127) {
                $decodedData = substr($bytes, 10);
            } else {
                $decodedData = substr($bytes, 2);
            }
        }

        return $decodedData;
    }

    public function console($msg="") {
        echo $msg . "\n";
    }

    public function wrap($type, $author, $content){
        return $msg ="{\"type\":\"$type\", \"author\": \"$author\", \"content\": $content}";
    }

    public function broadcast_group($user, $key, $msg){
        for( $i = 0 ;$i < count($this->groups[$key]) ; ++$i){
            if($this->groups[$key][$i] != $user && $this->groups[$key][$i] != null){
                $client = $this->groups[$key][$i];
                $this->send( $client->socket, $msg);
            }
        }
    }

     public function broadcast($msg){ // broadcast for the others user
        for( $i = 0 ;$i < count($this->frees) ; ++$i){
                $this->send( $this->frees[$i]->socket, $msg);
        }
    }

    public function findGroup($user){
        for( $i = 0 ; $i < count($this->groups) ; ++$i)
            for( $j = 0 ; $j < count($this->groups[$i]) ; ++$j){
                if( $this->groups[$i][$j] == $user)
                        return $i;
            }
            return -1;
    }

    public function getLargestKey(){
        return count($this->groups);
    }

    public function addToGroup($key, $user) {
        $this->groups[$key][] = $user;
    }

    public function countGroup($key){
        if($this->groups[$key]!=null){
            return count($this->groups[$key]);
        }
        else return 0;
    }

    public function outGroup($user){         
        for( $i = 0 ; $i < count($this->groups) ; ++$i){
            for( $j = 0 ; $j < count($this->groups[$i]) ; ++$j)
                if( $this->groups[$i][$j] == $user){  // delete user from groups
                     array_splice($this->groups[$i], $j, 1);
                     if($this->countGroup($i) == 0 || ($this->countGroup($i) == 1 && $this->groups[$i][0]->getName() == 0)){    // delete group with none user
                         array_splice($this->groups, $i, 1);
                         unset($this->questions[$i]);
                     }
                    return;
                }
        }
    }

    public function  getListRoom($current){
        $display = 8;
        $icurr = 0;
        $room = new ListRoom();
        foreach ($this->groups as $group) {            
            if(($icurr >= ($current-1)*$display) && ($icurr < $current*$display)){
                $id = $this->findGroup($group[0]);
                if( $this->playing[$id] != 1){  // only get room which is not playing
                    $room->thanhvien[] = count($group);
                    $room->id[] = $id;
                    $room->type_question[] = $this->type_question[$id];
                }
            }
            $icurr++;
        }
        $room->slg = ceil(count($this->groups)/$display); // page
        return $room;
    }

    public function getHost($key){
        for( $i = 0 ; $i < count($this->groups[$key]) ; ++$i)
            if( $this->groups[$key][$i]->getHost())
                    return $this->groups[$key][$i];
        return null;
    }

    public function setHost($user, $key){
        $user->setReady(0);
        $user->setHost(0);
        for( $i = 0 ; $i < count($this->groups[$key]) ; ++$i)
        {
            if( $this->groups[$key][$i]!= $user){
                $this->groups[$key][$i]->setHost(1);
                return 1;
            }
        }
        return 0;
    }

    public function outFreesArray($user){
        $sKey = array_search($user, $this->frees);
        
            if ($this->frees[$sKey]==$user) {
            array_splice($this->frees, $sKey, 1);
            }
           
    }

    public function outPlayingArray($Key){
            if ($this->playing[$Key] == 1) {
                $this->playing[$Key] = 0;
            }

    }

    public function getListQuestion1() {              
        $conn1 = new Connect();
        $conn = $conn1->open();

        $query = 'SELECT * FROM question WHERE id >= (SELECT FLOOR( MAX(id) * RAND()) FROM question ) ORDER BY id LIMIT '.$this->iNumQuestion;
        $result = mysql_query($query, $conn) or die("Could not connect").mysql_error();
        $questions = array();
        while($set = mysql_fetch_array($result, MYSQLI_ASSOC))
        {
            $temp = new Ques1();
            $temp->id = $set['id'];
            $temp->type = $set['id_type'];
            $temp->title = $set['title'];
            $temp->answer1 = $set['answerA'];
            $temp->answer2 = $set['answerB'];
            $temp->answer3 = $set['answerC'];
            $temp->answer4 = $set['answerD'];
            $temp->answer5 = $set['answerOK'];
            $questions[] = $temp;
        }
        mysql_close($conn);
           return $questions;
    }

    public function getListQuestion2() {
        $conn1 = new Connect();
        $conn = $conn1->open();

        $query = 'SELECT * FROM `audio-entity` WHERE id >= (SELECT FLOOR( MAX(id) * RAND()) FROM `audio-entity` ) ORDER BY id LIMIT '.$this->iNumQuestion;
        $result = mysql_query($query, $conn) or die("Could not connect").mysql_error();
        $questions = array();
        while($set = mysql_fetch_array($result, MYSQLI_ASSOC))
        {
            $temp = new Ques2();
            $temp->id = $set['id'];
            $temp->type = $set['id_type'];
            $temp->url = $set['url'];
            $temp->correct = $set['correct'];
            $questions[] = $temp;
        }
        mysql_close($conn);
           return $questions;
    }

    public function getQuestion_fromCalendar($key){
        $i = ceil($this->iNumQuestion/(count($this->groups[$key]))); // Tinh so luong trung binh cua so luong tu vung o moi nguoi choi
        $this->console($i."\n");
        $conn1 = new Connect();
        $conn = $conn1->open();
        $questions = array();
        for( $j = 0 ; $j < count($this->groups[$key]) ; ++$j){
            $query = 'SELECT * FROM saveword WHERE id_user = '.$this->groups[$key][$j]->getName().' ORDER BY dateInput LIMIT '.$i;
            $result = mysql_query($query, $conn) or die("Could not connect").mysql_error();            
            while($set = mysql_fetch_array($result, MYSQLI_ASSOC))
            {
                $temp = new Ques1();
                $temp->id = $set['id'];
                $temp->type = 1;
                $temp->title = $set['vietnameseString'];
                $rand = rand(1, 4);
                $query1 = 'SELECT englishString FROM saveword WHERE id >= (SELECT FLOOR( MAX(id) * RAND()) FROM saveword ) ORDER BY dateInput ASC LIMIT 4';
                $result1 = mysql_query($query1, $conn);
                switch ($rand) {
                    case 1:
                        $temp->answer1 = $set['englishString'];
                        
                        if( mysql_result($result1, 0) != $temp->answer1)
                            $temp->answer2 = mysql_result($result1, 0);
                        if( mysql_result($result1, 1) != $temp->answer1)
                            $temp->answer3 = mysql_result($result1, 1);
                        if( mysql_result($result1, 2) != $temp->answer1)
                            $temp->answer4 = mysql_result($result1, 2);

                        if( $temp->answer2 == null)
                            $temp->answer2 = mysql_result($result1, 3);
                        else if( $temp->answer3 == null)
                            $temp->answer3 = mysql_result($result1, 3);
                        else if( $temp->answer4 == null)
                            $temp->answer4 = mysql_result($result1, 3);
                        break;
                    case 2:
                        $temp->answer2 = $set['englishString'];

                        $result1 = mysql_query($query1, $conn);
                        if( mysql_result($result1, 0) != $temp->answer2)
                            $temp->answer1 = mysql_result($result1, 0);
                        if( mysql_result($result1, 1) != $temp->answer2)
                            $temp->answer3 = mysql_result($result1, 1);
                        if( mysql_result($result1, 2) != $temp->answer2)
                            $temp->answer4 = mysql_result($result1, 2);

                        if( $temp->answer1 == null)
                            $temp->answer1 = mysql_result($result1, 3);
                        else if( $temp->answer3 == null)
                            $temp->answer3 = mysql_result($result1, 3);
                        else if( $temp->answer4 == null)
                            $temp->answer4 = mysql_result($result1, 3);
                        break;
                    case 3:
                        $temp->answer3 = $set['englishString'];

                        $result1 = mysql_query($query1, $conn);
                        if( mysql_result($result1, 0) != $temp->answer3)
                            $temp->answer1 = mysql_result($result1, 0);
                        if( mysql_result($result1, 1) != $temp->answer3)
                            $temp->answer2 = mysql_result($result1, 1);
                        if( mysql_result($result1, 2) != $temp->answer3)
                            $temp->answer4 = mysql_result($result1, 2);

                        if( $temp->answer1 == null)
                            $temp->answer1 = mysql_result($result1, 3);
                        else if( $temp->answer2 == null)
                            $temp->answer2 = mysql_result($result1, 3);
                        else if( $temp->answer4 == null)
                            $temp->answer4 = mysql_result($result1, 3);
                        break;
                    case 4:
                        $temp->answer4 = $set['englishString'];

                        $result1 = mysql_query($query1, $conn);
                        if( mysql_result($result1, 0) != $temp->answer4)
                            $temp->answer1 = mysql_result($result1, 0);
                        if( mysql_result($result1, 1) != $temp->answer4)
                            $temp->answer2 = mysql_result($result1, 1);
                        if( mysql_result($result1, 2) != $temp->answer4)
                            $temp->answer3 = mysql_result($result1, 2);

                        if( $temp->answer1 == null)
                            $temp->answer1 = mysql_result($result1, 3);
                        else if( $temp->answer2 == null)
                            $temp->answer2 = mysql_result($result1, 3);
                        else if( $temp->answer3 == null)
                            $temp->answer3 = mysql_result($result1, 3);
                        break;
                    default:
                        break;
                }
                $temp->answer5 = $rand;
                $questions[] = $temp;
            }
        }
        mysql_close($conn);
        return $questions;
    }

    public function get_user($author){
        $connection = mysql_connect("localhost", "root", "");
       if( !$connection)
               die("Not connected: ". mysql_error ());
       mysql_select_db("elgg", $connection)
               or die("Could not select DB" . mysql_error());

                $query = "SELECT name FROM elgg_users_entity WHERE guid = $author";
                $result = mysql_query($query, $connection) or die("Could not connect").mysql_error();
                $name = mysql_fetch_row($result);
                mysql_close($connection);
                if( $name)
                    return $name;
                return -1;
    }
}

class ListRoom{
    var $slg = 0;
    var $thanhvien = array();
    var $id = array();
    var $type_question = array();
}

class Room{
    var $name = array();
    var $player = array();// id of player
    var $ready = array();
    var $host;
}

class RightAnswer{
    var $player = array();
    var $right = array();
}

class Connect {

    //put your code here
    public $connection;// = mysql_connect('localhost', 'myuser', '123456') ;

    public function   __construct() {
        $this->connection = null;
    }
    public function open()
    {
       $this->connection = mysql_connect("localhost", "root", "");
       if( !$this->connection)
               die("Not connected: ". mysql_error ());
       mysql_select_db("toihoctienganh", $this->connection)
               or die("Could not select DB" . mysql_error());
       return $this->connection;
    }


}

class Ques {
    public $id;
    public $type;

    public function   __construct() {
        $this->id = null;
        $this->type = 0;
    }
}

class Ques1 extends Ques{
    //put your code here
    
    public $title;
    public $answer1;
    public $answer2;
    public $answer3;
    public $answer4;
    public $answer5;

    public function   __construct() {        
        $this->title = null;
        $this->answer1 = null;
        $this->answer2 = null;
        $this->answer3 = null;
        $this->answer4 = null;
        $this->answer5 = null;

    }
}

class Ques2 extends Ques{
    public $url;
    public $correct;

    public function   __construct() {
        $this->url = "";
        $this->correct = 1;
    }
}
?>
